using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Threading;
using MusicPlayerAddIn.Properties;
using ViewOnCore.Helper.WPF;
using ViewOnCore.HostContract;
using ViewOnCore.HostContract.Media;
using ViewOnCore.Device;

namespace UI.Control
{

	// Ajouter :
	//  - Taille prise par la selection actuelle
	public partial class BurnDialog : System.Windows.Controls.UserControl
	{

		#region Variables

		private List<MediaData> _medias;

		private long _totalMediasDuration = 0;
		private long _totalMediasSize = 0;

		#endregion

		#region Constructor

		public BurnDialog(List<MediaData> medias)
		{
            _medias = medias;

			InitializeComponent();

			//----
			rbAudio.IsEnabled = false;
			rbData.IsEnabled = false;
			btnBurn.IsEnabled = false;
			btnExit.IsEnabled = false;
			cboDrives.IsEnabled = false;
			cboDriveSpeeds.IsEnabled = false;
			
			rbAudio.Checked += new RoutedEventHandler(rbAudio_Checked);
			rbAudio.Unchecked += new RoutedEventHandler(rbAudio_Unchecked);
			rbData.Checked += new RoutedEventHandler(rbData_Checked);
			rbData.Unchecked += new RoutedEventHandler(rbData_Unchecked);

			childWindowDecorator.VisuallyReady += new EventHandler(childWindowDecorator_VisuallyReady);
		}

		void childWindowDecorator_VisuallyReady(object sender, EventArgs e)
		{
			ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncUpdateDialog));
		}

		private void AsyncUpdateDialog(object state)
		{
            List<BurningDriveInfo> drives = Host.BurningService.BurningDevices;

			CalculateTotalMediasDuration();
			CalculateTotalMediasSize();

			Dispatcher.Invoke(
				System.Windows.Threading.DispatcherPriority.Normal,
				(DelegateInvoker)delegate { UpdateDialog(drives); });
		}

        private void UpdateDialog(List<BurningDriveInfo> drives)
		{
			//---- Set up the drives
            foreach (BurningDriveInfo driveInfo in drives)
			{
				string driveName = "[" + driveInfo.Letter + ":] " + driveInfo.Vendor + " " + driveInfo.Product;

				cboDrives.Items.Add(driveName);
			}

			//---- Select a drive
			cboDrives.SelectionChanged += new SelectionChangedEventHandler(cboDrives_SelectionChanged);
			cboDrives.SelectedIndex = 0;

			UpdateDuration();

			//---- Allow interaction
			rbAudio.IsEnabled = true;
			rbData.IsEnabled = true;
			btnBurn.IsEnabled = true;
			btnExit.IsEnabled = true;
			cboDrives.IsEnabled = true;
			cboDriveSpeeds.IsEnabled = true;
		}

		#endregion

		#region Ok / Cancel

		private void btnBurn_Click(object sender, System.Windows.RoutedEventArgs e)
		{
			StartBurning();
		}

		private void btnExit_Click(object sender, System.Windows.RoutedEventArgs e)
		{
            this.childWindowDecorator.Close();
		}

		private void btnCancel_Click(object sender, System.Windows.RoutedEventArgs e)
		{
			CancelBurning();
		}

		#endregion

		#region Change Burning mode

		void rbData_Unchecked(object sender, RoutedEventArgs e)
		{
		}

		void rbData_Checked(object sender, RoutedEventArgs e)
		{
			SetDataBurningMode();;
		}

		void rbAudio_Unchecked(object sender, RoutedEventArgs e)
		{
		}

		void rbAudio_Checked(object sender, RoutedEventArgs e)
		{
			SetAudioBurningMode();;
		}

		#endregion

		#region Set burning mode

		private void SetAudioBurningMode()
		{
            Host.BurningService.BurningMode = BurningMode.Audio;
			chkVerify.Visibility = Visibility.Collapsed;

			UpdateDuration();
		}

		private void SetDataBurningMode()
		{
            Host.BurningService.BurningMode = BurningMode.Data;
			chkVerify.Visibility = Visibility.Visible;

			UpdateDuration();
		}

		#endregion

		#region Drive selection

		void cboDrives_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			SelectDrive(cboDrives.SelectedIndex);
		}

		private void SelectDrive(int index)
		{
            BurningDriveInfo driveInfo = Host.BurningService.BurningDevices[index];
            List<BurningDriveSpeed> speeds = driveInfo.SupportedWriteSpeeds;
            foreach (BurningDriveSpeed driveSpeed in speeds)
			{
                string speed = driveSpeed.SpeedRatio + "x (" + driveSpeed.Speed + " " + Globalization.KiloBytesSeconds + ")";

				cboDriveSpeeds.Items.Add(speed);

				// Select the current speed
                if (driveInfo.WriteSpeed == driveSpeed.Speed)
					cboDriveSpeeds.SelectedIndex = cboDriveSpeeds.Items.Count - 1;
			}
		}

		#endregion

		#region Properties

		public BurningDriveInfo CurrentDrive
		{
			get
			{
				return Host.BurningService.BurningDevices[cboDrives.SelectedIndex];
			}
		}

		public BurningDriveSpeed CurrentDriveSpeed
		{
			get
			{
				return CurrentDrive.SupportedWriteSpeeds[cboDriveSpeeds.SelectedIndex];
			}
		}

		#endregion

		#region StartBurning

		private void StartBurning()
		{
			ShowErrorMessage("");

			//---- Change buttons
			btnBurn.Visibility = Visibility.Collapsed;
			btnExit.Visibility = Visibility.Collapsed;
			btnCancel.Visibility = Visibility.Visible;

			txtStatus.Visibility = Visibility.Visible;
			txtProgress.Visibility = Visibility.Visible;

			cboDrives.IsEnabled = false;
			cboDriveSpeeds.IsEnabled = false;
			chkVerify.IsEnabled = false;

			rbAudio.IsEnabled = false;
			rbData.IsEnabled = false;

			//---- Start the spinner
			spinner.Start();

			//---- Update informations
			Host.BurningService.Refresh();

			ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncBurn), new object[] { CurrentDrive, CurrentDriveSpeed, chkVerify.IsChecked });
		}

		private void AsyncBurn(object state)
		{
			object[] values = (object[])state;
            BurningDriveInfo currentDrive = values[0] as BurningDriveInfo;
            BurningDriveSpeed currentDriveSpeed = values[1] as BurningDriveSpeed;
			bool verify = (bool)values[2];

            string errorMessage = Host.BurningService.ValidateBurningData(currentDrive);
			if (errorMessage != null)
			{
				ShowErrorMessage(errorMessage);
				Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
									(DelegateInvoker)delegate { OnBurningEnd(); });
				return;
			}

            Host.BurningService.BurningStatusChanged += new BurningServiceStatusEventHandler(OnBurningStatusChanged);
            Host.BurningService.BurningProgressChanged += new BurningServiceProgressEventHandler(OnBurningProgressChanged);
            Host.BurningService.BurningErrorOccured += new BurningServiceErrorEventHandler(OnBurningErrorOccured);

            Host.BurningService.Burn(_medias, currentDrive, currentDriveSpeed, verify);

            Host.BurningService.BurningStatusChanged -= new BurningServiceStatusEventHandler(OnBurningStatusChanged);
            Host.BurningService.BurningProgressChanged -= new BurningServiceProgressEventHandler(OnBurningProgressChanged);
            Host.BurningService.BurningErrorOccured -= new BurningServiceErrorEventHandler(OnBurningErrorOccured);

			Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
									(DelegateInvoker)delegate { OnBurningEnd(); });
		}

		private void OnBurningEnd()
		{
			//---- Stop the spinner
			spinner.Stop();

			txtStatus.Visibility = Visibility.Hidden;
			txtProgress.Visibility = Visibility.Hidden;

			cboDrives.IsEnabled = true;
			cboDriveSpeeds.IsEnabled = true;
			chkVerify.IsEnabled = true;

			rbAudio.IsEnabled = true;
			rbData.IsEnabled = true;

			//---- Change buttons
			btnBurn.Visibility = Visibility.Visible;
			btnExit.Visibility = Visibility.Visible;
			btnCancel.Visibility = Visibility.Collapsed;
		}

		#endregion

		#region CancelBurning

		private void CancelBurning()
		{
			Host.BurningService.CancelBurn();

			//---- Stop the spinner
			spinner.Stop();

			txtStatus.Visibility = Visibility.Collapsed;

			//---- Change buttons
			btnBurn.Visibility = Visibility.Visible;
			btnExit.Visibility = Visibility.Visible;
			btnCancel.Visibility = Visibility.Collapsed;
		}

		#endregion

		#region OnBurningStatusChanged

		public void OnBurningStatusChanged(string statusMessage)
		{
			Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
							(DelegateInvoker)delegate { txtStatus.Text = statusMessage; });
		}

		#endregion

		#region OnBurningProgressChanged

		public void OnBurningProgressChanged(BurningStep step, int percent, int timeRemaining)
		{
			Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
							(DelegateInvoker)delegate { txtProgress.Text = percent + " %"; });
		}

		#endregion

		#region Calculate Durations

		private void CalculateTotalMediasDuration()
		{
			_totalMediasDuration = 0;
			foreach (MediaData media in _medias)
				try
				{
					_totalMediasDuration += Host.MediaService.GetFileTotalTime(media.Path);
				}
				catch
				{
				}
		}

		private void CalculateTotalMediasSize()
		{
			_totalMediasSize = 0;
			foreach (MediaData media in _medias)
				try
				{
					_totalMediasSize += new System.IO.FileInfo(media.Path).Length;
				}
				catch
				{
				}
		}

		#endregion

		#region UpdateDuration

		private void UpdateDuration()
		{
            if (Host.BurningService.BurningMode == BurningMode.Audio)
			{
				Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
				(DelegateInvoker)delegate { AsyncUpdateDurationForAudio(); });
			}
			else
			{
				Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
				(DelegateInvoker)delegate { AsyncUpdateDurationForData(); });
			}
		}

		private void AsyncUpdateDurationForAudio()
		{
			TimeSpan duration = new TimeSpan(_totalMediasDuration * TimeSpan.TicksPerSecond);
			txtSize.Text = duration.ToString();

            if (CurrentDrive.DiscTotalSize > 0)
			{
                txtMaxSize.Text = Host.BurningService.ConvertToTime(CurrentDrive.DiscTotalSize).ToString();

                long percents = (100 * _totalMediasDuration * TimeSpan.TicksPerSecond) / Host.BurningService.ConvertToTime(CurrentDrive.DiscTotalSize).Ticks;
				prgSize.Value = percents;
			}
			else
			{
				txtMaxSize.Text = "/";
				prgSize.Value = 0;
			}
		}

		private void AsyncUpdateDurationForData()
		{
			txtSize.Text = (_totalMediasSize / (1024 * 1024)).ToString() + " " + Globalization.MegaBytes;

            if (CurrentDrive.DiscTotalSize > 0)
			{
                txtMaxSize.Text = (Host.BurningService.ConvertToBytes(CurrentDrive.DiscTotalSize) / (1024 * 1024)) + " " + Globalization.MegaBytes;

                prgSize.Value = (100 * _totalMediasSize / Host.BurningService.ConvertToBytes(CurrentDrive.DiscTotalSize));
			}
			else
			{
				txtMaxSize.Text = "/";
				prgSize.Value = 0;
			}
		}

		#endregion

		#region OnBurningErrorOccured

		public void OnBurningErrorOccured(string errorMessage)
		{
			ShowErrorMessage(errorMessage);
		}

		#endregion

		#region ShowErrorMessage

		public void ShowErrorMessage(string message)
		{
			Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
					(DelegateInvoker)delegate { txtErrorMessage.Text = message; });
		}

		#endregion

        #region ShowDialog

        /// <summary>
        /// Show the dialog.
        /// </summary>
        /// <param name="container">The desktop</param>
        /// <param name="handler">This handler handle when the dialog is closed</param>
        public void ShowDialog(Desktop container, ChildWindowDialogClosedHandler handler)
        {
            childWindowDecorator.ShowDialog(container, handler);
        }

        /// <summary>
        /// Show the dialog.
        /// </summary>
        /// <param name="container">The desktop</param>
        public void ShowDialog(Desktop container)
        {
            childWindowDecorator.ShowDialog(container);
        }

        #endregion

	}

}